/*******************************************************************************
 *
 *    Copyright (c) Baina Info Tech Co. Ltd
 *
 *    MoboTap Client
 * 
 *    JsonWebServiceClient
 *
 *    @author: chzhong
 *    @since:  2010-8-10
 *    @version: 1.0
 *
 ******************************************************************************/

package com.sdk.network;

import java.util.Map;

import org.apache.http.HttpEntity;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONStringer;

import android.text.TextUtils;

import com.sdk.util.Log;


/**
 * 一般的网络访问可以直接继承该类，来完成构造Url，和执行网络请求的操作。
 * @author chzhong
 *
 */
public abstract class JsonWebServiceClient extends WebServiceClient {

    /**
     * NULL
     */
    private static final String NULL = "null";
    private static final String TAG = JsonWebServiceClient.class.getSimpleName();

    /**
     * Decode the {@linkplain HttpEntity} as a {@linkplain JSONArray}.
     * @param entity the {@linkplain HttpEntity} to decode.
     * @return the {@linkplain JSONArray} result, or null.
     */
    public static final JSONArray decodeEntityAsJSONArray(final HttpEntity entity) {
        final String json = decodeEntityAsString(entity);
        if(!TextUtils.isEmpty(json)){
            JSONArray jsonArray = null;
            try {
                jsonArray = new JSONArray(json);
            } catch (final JSONException e) {
                Log.e(TAG, "Failed to parse string as JSON object.");
                Log.e(TAG, "Ordinary JSON: %s", json);
                e.printStackTrace();
            }
            return jsonArray;
        }else{
            return null;
        }
    }

    /**
     * Decode the {@linkplain HttpEntity} as a {@linkplain JSONObject}.
     * @param entity the {@linkplain HttpEntity} to decode.
     * @return the {@linkplain JSONObject} result, or null.
     */
    public static final JSONObject decodeEntityAsJSONObject(final HttpEntity entity) {
        final String json = decodeEntityAsString(entity);
        JSONObject jsonObject = null;
        if(!TextUtils.isEmpty(json)){
            try {
                jsonObject = new JSONObject(json);
            } catch (final JSONException e) {
                Log.e(TAG, "Failed to parse string as JSON object.");
                Log.e(TAG, "Ordinary JSON: %s", json);
                e.printStackTrace();
            }
        }
        return jsonObject;
    }

    /**
     * Add a property to  current {@linkplain JSONStringer}.
     * @param stringer the {@linkplain JSONStringer}.
     * @param key the name of the property.
     * @param value the value.
     * @throws JSONException If the key or value is out of place. For example, keys do not belong in arrays or if the key is null.
     */
    public static final void addProperty(final JSONStringer stringer, final String key, final Object value) throws JSONException {
        stringer.key(key);
        stringer.value(value);
    }

    /**
     * Add a property to  current {@linkplain JSONStringer}.
     * @param stringer the {@linkplain JSONStringer}.
     * @param key the name of the property.
     * @param value the value.
     * @throws JSONException If the key or value is out of place. For example, keys do not belong in arrays or if the key is null.
     */
    public static final void addProperty(final JSONStringer stringer, final String key, final boolean value) throws JSONException {
        stringer.key(key);
        stringer.value(value);
    }

    /**
     * Add a property to  current {@linkplain JSONStringer}.
     * @param stringer the {@linkplain JSONStringer}.
     * @param key the name of the property.
     * @param value the value.
     * @throws JSONException If the key or value is out of place. For example, keys do not belong in arrays or if the key is null.
     */
    public static final void addProperty(final JSONStringer stringer, final String key, final double value) throws JSONException {
        stringer.key(key);
        stringer.value(value);
    }

    /**
     * Add a property to  current {@linkplain JSONStringer}.
     * @param stringer the {@linkplain JSONStringer}.
     * @param key the name of the property.
     * @param value the value.
     * @throws JSONException If the key or value is out of place. For example, keys do not belong in arrays or if the key is null.
     */
    public static final void addProperty(final JSONStringer stringer, final String key, final long value) throws JSONException {
        stringer.key(key);
        stringer.value(value);
    }

    /**
     * Initiate a new instance of {@link JsonWebServiceClient}.
     * @param serverUrl
     */
    public JsonWebServiceClient(final String serverUrl) {
        super(serverUrl);
    }

    /**
     * Retrieve the content of the URL as {@linkplain JSONObject}.
     * @param url The URL to retrieve.
     * @return The content of the given URL, or null if error occurred.
     */
    protected final JSONObject getUrlAsJSONObject(final String url) {
        final String json = getUrlAsString(url);
        if (TextUtils.isEmpty(json) || NULL.equalsIgnoreCase(json)) {
            Log.w(TAG, "The returned JSON is \"%s\".", json == NULL ? "<null>" : json);
        } else {
            try {
                return new JSONObject(json);
            } catch (final JSONException e) {
                Log.e(TAG, "Failed to parse string as JSON object.");
                Log.e(TAG, "Ordinary JSON: %s", json);
                e.printStackTrace();
            }
        }
        return null;
    }


    /**
     * Retrieve the content of the URL as {@linkplain JSONArray}.
     * @param url The URL to retrieve.
     * @return The content of the given URL, or null if error occurred.
     */
    protected final JSONArray getUrlAsJSONArray(final String url) {
        String json = getUrlAsString(url);
        Log.d(TAG, "recommendation json string:"+json);
        if(null == json){
            return null;
        }else if ("".equals(json) || NULL.equalsIgnoreCase(json)) {
            Log.w(TAG, "The returned JSON is \"%s\".", json == NULL ? "<null>" : json);
            json = "[]";
        }
        JSONArray array = null;
        try {
            array = new JSONArray(json);
        } catch (final JSONException e) {
            Log.e(TAG, "Failed to parse string as JSON array.");
            Log.e(TAG, "Ordinary JSON: %s", json);
            e.printStackTrace();
        }
        return array;
    }

    /**
     * 
     * @param urlBuilder
     * @return
     */
    protected final JSONArray getUrlBuilderAsJSONArray(final WebServiceUrlBuilder urlBuilder){
        if(null == urlBuilder){
            throw new IllegalArgumentException("Url builder must not be null");
        }
        return getUrlAsJSONArray(urlBuilder.build());
    }

    /**
     * Post content to the given url.
     * @param url the url of the content.
     * @param content the content to post
     * @return true for success, false otherwise.
     */
    protected final boolean postContent(final String url, final JSONStringer content) {
        return postContent(url, content.toString());
    }

    /**
     * Post content to the given url.
     * @param url the url of the content.
     * @param content the content to post
     * @return true for success, false otherwise.
     */
    protected final boolean postContent(final String url, final JSONObject object) {
        return postContent(url, object.toString());
    }

    /**
     * Post content to the given url.
     * @param url the url of the content.
     * @param content the content to post
     * @return true for success, false otherwise.
     */
    protected final boolean postContent(final String url, final JSONArray array) {
        return postContent(url, array.toString());
    }

    /**
     * Post content to the given url.
     * @param url the url of the content.
     * @param content the content to post
     * @return true for success, false otherwise.
     */
    protected final boolean postContent(final String url, final Map<?, ?> values) {
        return postContent(url, new JSONObject(values));
    }

    /**
     * Post content to the given url.
     * @param url the url of the content.
     * @param content the content to post
     * @return true for success, false otherwise.
     */
    protected final HttpEntity postContentForEntity(final String url, final JSONStringer content) {
        return postContentForEntity(url, content.toString());
    }

    /**
     * Post content to the given url.
     * @param url the url of the content.
     * @param content the content to post
     * @return true for success, false otherwise.
     */
    protected final HttpEntity postContentForEntity(final String url, final JSONObject object) {
        return postContentForEntity(url, object.toString());
    }

    /**
     * Post content to the given url.
     * @param url the url of the content.
     * @param content the content to post
     * @return true for success, false otherwise.
     */
    protected final HttpEntity postContentForEntity(final String url, final JSONArray array) {
        return postContentForEntity(url, array.toString());
    }

    /**
     * Post content to the given url.
     * @param url the url of the content.
     * @param content the content to post
     * @return true for success, false otherwise.
     */
    protected final HttpEntity postContentForEntity(final String url, final Map<?, ?> values) {
        return postContentForEntity(url, new JSONObject(values));
    }
}
